#include <NTPClient.h>
#include <WiFi.h> // for WiFi shield
#include <WiFiUDP.h>
#include <SPI.h>
#include <TFT_eSPI.h>
#include <ArduinoJson.h> //Json库
#include <HTTPClient.h>  //HTTP库
#include "MyFont.h"
#include "astronauts.h" //图片库
#include "pic.h" //图片库

TFT_eSPI tft = TFT_eSPI();
TFT_eSprite clk = TFT_eSprite(&tft);
const char *ssid = "Laboratory";           //wifi账号
const char *password = "xxgcx303";         //wifi密码
const char *host = "api.seniverse.com";    //心知天气服务器地址
const char *host_location = "pv.sohu.com"; //搜狐服务器地址

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "ntp.aliyun.com"); //NTP服务器地址
unsigned long timers = 0;                                 //控制图片切换时间延时

/***************************单个汉字显示*****************************/
void showMyFont(int32_t x, int32_t y, const char c[3], uint32_t color) { 
  for (int k = 0; k < 40; k++)// 根据字库的字数调节循环的次数
    if (hanzi[k].Index[0] == c[0] && hanzi[k].Index[1] == c[1] && hanzi[k].Index[2] == c[2])
    { 
        clk.drawBitmap(x, y, hanzi[k].hz_Id, hanzi[k].hz_width, 16, color);
    }
}

/************************整句汉字显示***************************/
void showMyFonts(int32_t x, int32_t y, const char str[], uint32_t color) { //显示整句汉字，字库比较简单，上下、左右输出是在函数内实现
  int x0 = x;
  for (int i = 0; i < strlen(str); i += 3) {
    showMyFont(x0, y, str+i, color);
    x0 += 17;
  }
}

/************************WIFI连接展示***************************/
void Wifi_Connection_Show()
{
  static unsigned char j = 0;
  if (timers == 0)
  {
    tft.pushImage(30, 28, 69, 100, WangWang[0]);
    timers = millis();
  }
  else
  {
    if (millis() - timers >= 300)
    {
      if (++j == 6)
      {
        j = 0;
      }
      tft.pushImage(30, 28, 69, 100, WangWang[j]);
      timers = millis();
    }
  }
}

/****************************太空人动态显示函数**********************************************/
void Show_astronaut()
{
  static unsigned long timer_as = 0;
  static unsigned char i = 0;
  if (timer_as == 0)
  {
    tft.pushImage(83, 83, 45, 45, Astronaut[0]);
    timer_as = millis();
  }
  else
  {
    if (millis() - timer_as >= 150)
    { //调节图片轮播帧数（九张图）
      if (++i == 9)
      {
        i = 0;
      }
      tft.pushImage(83, 83, 45, 45, Astronaut[i]);
      timer_as = millis();
    }
  }
}

/************************系统内置函数wifi连接函数***************************/
bool Original_Wifi_Connection()
{
  Serial.println("Start the built-in network connection");
  int timer = millis();
  bool connection = false;
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    Wifi_Connection_Show();
    delay(200);
    Serial.print(".");
    //用这个函数来判断连接时间长度 millis(); 获取系统当前运行时间单位ms
    if ((millis() - timer) > 20000)
    { //连接持续时间不超过20s
      break;
    }
  }
  Serial.println("");
  if (WiFi.status() == WL_CONNECTED)
  {
    tft.pushImage(0, 0, 128, 128, jiazaiwancheng);
    Serial.println("Network connection succeeded！！！");
    connection = true;
  }
  else
  {
    Serial.println("Network connection timeout。。。");
  }

  return connection;
}

/************************手机端APP广播连接wifi***************************/
void Wifi_SmartConfig()
{
  WiFi.reconnect();
  //Init WiFi as Station, start SmartConfig
  WiFi.mode(WIFI_AP_STA);
  WiFi.beginSmartConfig();

  //Wait for SmartConfig packet from mobile
  Serial.println("Waiting for SmartConfig.");
  while (!WiFi.smartConfigDone())
  {
    delay(500);
    Serial.print(".");
    Wifi_Connection_Show();
  }

  Serial.println("");
  Serial.println("SmartConfig received.");

  //Wait for WiFi to connect to AP
  Serial.println("Waiting for WiFi");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("Network connection succeeded！！！");
  tft.pushImage(0, 0, 128, 128, jiazaiwancheng);
}

//显示连接网络信息
void Show_network_information()
{
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  Serial.print("Signal strength: ");
  Serial.println(WiFi.RSSI());
}

/*****************************时间日期显示**************************************************/
void Obtaining_NTP_Time()
{
  static unsigned char miao = 0;
  static unsigned char week = 0;
  //更新时间
  timeClient.update();
  unsigned long epochTime = timeClient.getEpochTime();

  //打印时间
  int currentSecond = timeClient.getSeconds(); //秒

  int currentHour = timeClient.getHours(); //小时

  int currentMinute = timeClient.getMinutes(); //分钟

  if (miao != currentSecond)
  {
    clk.setColorDepth(8); //设置色深

    clk.createSprite(128, 38); //绘制窗口

    clk.fillSprite(0x0000); //填充率

    clk.fillSprite(TFT_BLACK); //设置背景色

    clk.setTextColor(TFT_WHITE, 0x0000); //设置字体颜色

    clk.setTextSize(2);

    clk.drawNumber(currentHour % 10, 25, 0, 4);
    clk.drawNumber(currentHour / 10, 0, 0, 4);

    clk.setTextColor(TFT_ORANGE, 0x0000); //设置字体颜色

    clk.drawNumber(currentMinute % 10, 75, 0, 4);
    clk.drawNumber(currentMinute / 10, 50, 0, 4);

    clk.setTextColor(TFT_GREEN, 0x0000); //设置字体颜色

    clk.setTextSize(2);

    clk.drawNumber(currentSecond % 10, 117, 24, 1);
    clk.drawNumber(currentSecond / 10, 105, 24, 1);

    clk.pushSprite(0, 42);

    miao = currentSecond;
  }

  //日期显示
  int weekDay = timeClient.getDay(); //星期

  //将epochTime换算成年月日
  struct tm *ptm = gmtime((time_t *)&epochTime);
  int monthDay = ptm->tm_mday;

  int currentMonth = ptm->tm_mon + 1;

  int currentYear = ptm->tm_year + 1900;

  if (week != weekDay)
  {
    clk.createSprite(83, 45); //绘制窗口

    clk.fillSprite(0x0000); //填充率

    clk.setTextColor(TFT_GREEN, 0x0000); //设置字体颜色

    clk.setTextSize(2);

    clk.drawNumber(currentYear, 1, 1, 1);

    showMyFont(48, 0, "年", TFT_YELLOW);

    clk.setTextSize(2);

    clk.drawNumber(currentMonth, 3, 24, 1);

    showMyFont(15, 23, "月", TFT_YELLOW);

    clk.drawNumber(monthDay, 32, 24, 1);

    showMyFont(43, 23, "日", TFT_YELLOW);

    clk.drawFastVLine(65, 0, 45, TFT_YELLOW);

    showMyFont(67, 0, "周", TFT_YELLOW);

    switch (weekDay)
    {
    case 1:
    showMyFont(67, 23, "一", TFT_YELLOW);
      break;
    case 2:
    showMyFont(67, 23, "二", TFT_YELLOW);
      break;
    case 3:
    showMyFont(67, 23, "三", TFT_YELLOW);
      break;
    case 4:
    showMyFont(67, 23, "四", TFT_YELLOW);
      break;
    case 5:
    showMyFont(67, 23, "五", TFT_YELLOW);
      break;
    case 6:
    showMyFont(67, 23, "六", TFT_YELLOW);
      break;
    case 7:
    showMyFont(67, 23, "日", TFT_YELLOW);
      break;
    }

    clk.pushSprite(0, 86);

    week = weekDay;
  }

  //Print complete date:
  String currentDate = String(currentYear) + "-" + String(currentMonth) + "-" + String(monthDay);
  Serial.print("Current date: ");
  Serial.println(currentDate);
  Serial.println("");
}

/*****************************天气显示**************************************************/
void Http_Im()
{
  //创建TCP连接
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host_location, httpPort))
  {
    Serial.println("connection failed"); //网络请求无响应打印连接失败
    return;
  }
  //URL请求地址
  String url_location = "/cityjson?ie=utf-8";

  //发送网络请求
  client.print(String("GET ") + url_location + " HTTP/1.1\r\n" +
               "Host: " + host_location + "\r\n" +
               "Connection: close\r\n\r\n");
  delay(1000);
  //定义location变量用来存放请求网络服务器后返回的数据
  String location;
  while (client.available())
  {
    String line = client.readStringUntil('\r');
    location += line;
  }

  //获得json格式的数据
  String jsonAnswer;
  int jsonIndex;
  //找到有用的返回数据位置i 返回头不要
  for (int i = 0; i < location.length(); i++)
  {
    if (location[i] == '{')
    {
      jsonIndex = i;
      break;
    }
  }
  jsonAnswer = location.substring(jsonIndex);
  Serial.println();
  Serial.println("JSON answer: ");
  Serial.println(jsonAnswer);

  //解析数据

  StaticJsonDocument<128> doc;

  deserializeJson(doc, jsonAnswer);

  const char *cname = doc["cname"]; // "湖北省孝感市"

  Serial.println(cname);
  Serial.println(String(cname));

  client.stop(); //断开服务器连接

  //重新连接
  if (!client.connect(host, httpPort))
  {
    Serial.println("connection failed"); //网络请求无响应打印连接失败
    return;
  }

  Serial.println("连接成功");

  String url = "/v3/weather/now.json?key=S-nEE55WjRq321EmY&location=" + String(cname) + "&language=zh-Hans&unit=c";
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: open\r\n\r\n");

  delay(1000);
  //定义location2变量用来存放请求网络服务器后返回的数据
  String location2;
  while (client.available())
  {
    String line2 = client.readStringUntil('\r');
    location2 += line2;
  }
  //解析数据
  String jsonAnswer2;
  int jsonIndex2;
  //找到有用的返回数据位置i 返回头不要
  for (int i = 0; i < location2.length(); i++)
  {
    if (location2[i] == '{')
    {
      jsonIndex2 = i;
      break;
    }
  }
  jsonAnswer2 = location2.substring(jsonIndex2);
  Serial.println();
  Serial.println("JSON answer2: ");
  Serial.println(jsonAnswer2);

  client.stop(); //断开服务器连接
  // Stream& input;

  StaticJsonDocument<512> docs;

  deserializeJson(docs, jsonAnswer2);
  JsonObject results_0 = docs["results"][0];
  JsonObject results_0_now = results_0["now"];
  const char *results_0_now_text = results_0_now["text"];               // "多云"
  const char *results_0_now_temperature = results_0_now["temperature"]; // "24"

  clk.setColorDepth(8); //设置色深

  clk.createSprite(128, 45); //绘制窗口

  clk.fillSprite(0x0000); //填充率

  clk.fillSprite(TFT_BLACK); //设置背景色

  showMyFonts(0,0,"当前气温",TFT_ORANGE);

  clk.setTextColor(TFT_GREEN, 0x0000); //设置字体颜色

  clk.setTextSize(2);
  
  clk.drawString(":"+String(results_0_now_temperature),69,0);

  showMyFont(106,0,"设",TFT_ORANGE);

  showMyFonts(30,21,"天气",TFT_ORANGE);

  clk.drawString(":",64,21);

  showMyFonts(78,21,results_0_now_text,TFT_ORANGE);

  clk.drawFastHLine(0,40,128,TFT_YELLOW);
  
  clk.pushSprite(0, 0);
}


void setup()
{
  tft.init();                //初始化显示寄存器
  tft.fillScreen(TFT_WHITE); //屏幕颜色
  tft.setSwapBytes(true);    //使图片颜色由BGR->RGB
  tft.setTextColor(TFT_BLACK);        //设置字体颜色黑色
  tft.setCursor(10, 8, 2);           //设置文字开始坐标(15,30)及1号字体
  tft.setTextSize(1);
  tft.println("Connecting Wifi...");
  //串口打印调试信息
  Serial.begin(115200);
  Serial.println("Start.....");
  //先进行内置WiFi连接
  if(!Original_Wifi_Connection())
  {
    //智能手机连接
    Wifi_SmartConfig();
  }

  //显示网络信息
  Show_network_information();
  delay(2000);
  tft.fillScreen(TFT_BLACK);    //清屏
  timers = millis();
  timeClient.begin();
  timeClient.setTimeOffset(28800); // + 1区 偏移3600， +8区 ：3600×8 = 28800
  Http_Im();
  Obtaining_NTP_Time();
}

void loop()
{
  Obtaining_NTP_Time();
  Show_astronaut();
  if (millis() - timers >= 600000)
  {
    Http_Im();
    timers = millis();
  }
  
}
